home *** CD-ROM | disk | FTP | other *** search
/ MacHack 1996 / MacHack 1996.toast / Presentations / Presentations ’96 / Sessions ’96 / Random Numbers / Random.c < prev    next >
Encoding:
Text File  |  1996-06-03  |  10.8 KB  |  331 lines  |  [TEXT/CWIE]

  1. //
  2. // Two-Stage Cryptographic Random Number Generator
  3. //
  4. // Copyright © 1996, Jon Callas, Eldacur Technologies. All Rights Reserved.
  5. //
  6. // You have permission to use this code in any commercial or non-commercial programs provided
  7. // you do the following:
  8. //
  9. // (1) Somewhere in your documentation, about box, etc. you state that you use Jon Callas's
  10. //     Two-Stage Random Number Generator and that it is copyright by him.
  11. // (2) If you use it in a commercial product, you send me email at jon@worldbenders.com telling me
  12. //     that you're using it. I don't have any nefarious purposes, I'm not going to sell your
  13. //     name to some mailing list, I just want to know who is using it, so I can send updates
  14. //     to you and be able to brag about the bizillion people that use this.
  15. // (3) If you find bugs, make substantive improvements, etc. that you make a best-faith effort
  16. //     to send them to me so I can incorporate it into the code.
  17. //
  18. // That's it. That's all you have to do. It's not much to ask. It's not as odious as a copyleft
  19. // so why not do it?
  20. //
  21.  
  22. #include "Random.h"
  23.  
  24. #ifdef COMPILE_COMMENTS
  25.  
  26. What this is:
  27.  
  28. This is a high-quality random number generator that can create large amounts of good random
  29. numbers. When used properly, it can hold up to 2048 bits of randomness, or entropy in it. This
  30. is more than enough for any purpose you need to use it for. However, like any piece of 
  31. precision machinery, it must be used properly and handled with care. 
  32.  
  33. Please take the care to read these instructions and follow them.
  34.  
  35. HOW TO USE IT
  36. --- -- --- --
  37.  
  38. The base object type is a Randomizer. There are also objects here for the two stages, the 
  39. Distiller and the Grinder. They'll be explained below. Usually you don't ever have to use them.
  40.  
  41. (1) Make a Randomizer. The statement:
  42.  
  43.     Randomizer *r = new Randomizer();
  44.     
  45. is good enough.
  46.  
  47. (2) Find a source of random inputs. Real random inputs. Best things to use are user-driven 
  48. inputs like mouse positions, timings of keystrokes, and stuff like that. Each observation you
  49. seed the Randomizer with should have a guess of how random it is, in decibits. Yeah, decibits.
  50. Tenths of bits. If you think it's as good as a coin toss (like the clock time), then it should 
  51. be 10. If it's a really mediocre observation, use 1. If it's junk that you're using because 
  52. you like it (like your ethernet address, contents of files, etc.) throw it into the mix, but 
  53. rate it 0. It all gets mixed up into the first stage, the Distiller. Hint: Always Guess Low, 
  54. Especially If You Are Writing Privacy Software! Once the Distiller is filled with enough 
  55. entropy, it will empty itself into the second stage. You can force the Distiller to empty
  56. by using a negative number for your entropy guesss.
  57.  
  58. Add in seed values with:
  59.  
  60.     r->AddSeed(sourcePtr, length, decibits);
  61.  
  62. For example, you'd add in a timing observation with:
  63.  
  64.     r->AddSeed(&timer, 4, 10);
  65.  
  66. You can find out how much entropy is in the system with the call:
  67.  
  68.     r->GetEntropy();
  69.  
  70. (3) You should make a habit of periodically adding stuff to the mix. Sample the mouse and put
  71. X,Y position in. Time how long it takes you to create, write garbage into, and delete a 1MB 
  72. file. Have fun. If you are in the habit of using a variety of observations, and mixing them in
  73. to the Randomizer, the accumulated entropy will help your system be random. And remember, when
  74. you guess about your randomness, guess low, especially in the things you gather in the 
  75. background!
  76.  
  77. (4) Get random values with these functions:
  78.  
  79.     r->Byte(); r->Word(); r->Long();
  80.  
  81. These return a random 8, 16, and 32 bit quantity respectively. The function:
  82.  
  83.     r->String(char *position, long size);
  84.  
  85. will fill the memory 'size' long pointed to by 'position' with random bytes.
  86.  
  87. (5) Saving State:
  88.  
  89. If you need to save the state of the Randomizer, you can call:
  90.  
  91.     r->GetState(RandomState *state);
  92.     r->SetState(RandomState *state);
  93.  
  94. to save and restore the state. You should consider the state of the randomizer to be sensitive
  95. data! Treat it with the same respect you would treat password files, private keys, and other
  96. sensitive data. Don't let an adversary break your privacy system by scamming your random 
  97. numbers!
  98.  
  99.  
  100. HOW IT WORKS
  101. --- -- -----
  102.  
  103. Stage 1 is the Distiller. It is a cryptographic checksum, specifically the Secure Hash Algorithm.
  104. The implementation of SHS I use here was written by Paul Kocher, given to me by Paul, and used with
  105. his kind permission.
  106.  
  107. A cryptographic checksum like this can be used to accumulate entropy. There is a problem when you
  108. toss together things you think are random. The problem is that they probably aren't as random as
  109. you think they are, and they probably aren't random in the way you think they are. The wonderful
  110. thing about a checksum like this is that it can distill all the entropy in your samples. It doesn't
  111. increase entropy, but it holds it up to its maximum (in the case of SHS, 160 bits). It can even be
  112. used in things that are weakly random.
  113.  
  114. An example of a weakly random source follows: Suppose you were sampling white noise from a 
  115. microphone in the lab you put your HoozieServer 2000 in. Let's also suppose that while it
  116. just sounds like hiss to you, if we do fourier analysis on the samples we find that it's all
  117. just a bunch of harmonics except for some small bit of noise that makes your sample be X mod Y
  118. one time in four, and A mod B the other three times in four. Depressing, huh? It's not hopeless,
  119. though. It does suck that you thought you were getting 16 bits of white noise on each sample of
  120. the microphone, but there is still some value here. There's actually a half-bit of randomness in 
  121. any sample you make. Yeah, fractional bits sound weird, but they really represent the flip of an 
  122. off-kilter coin. You can still use them, so long as you don't overestimate their value.
  123.  
  124. This is why I tell you to make many samples, and always guess low. Murphy *is* out to get you.
  125.  
  126. Once you have accumulated enough entropy in the Distiller, we move it to the second stage of the
  127. generator. I trust your guesses, when you tell me there's enough, I go for it. That's why I'm 
  128. being such a nag.
  129.  
  130. The second stage of the random number generator is a non-linear, arithmetic streamer. Its guts are 
  131. mathematically similar to some of the non-linear streams used in some high-performance 
  132. stream cyphers, but adapted to the needs of a random number generator, as opposed to a stream
  133. cypher. 
  134.  
  135. The combination of the two of them give you a way to hold up to 2048 bits of entropy and use it to
  136. generate crypto-quality random numbers. If you use it properly, it will serve you well. If you
  137. misuse it, don't come complaining to me.
  138.  
  139. If you need to know more about random numbers, what makes a good random number, why the rand() 
  140. function isn't good enough, or why things you think are random aren't, look at some of the
  141. following sources:
  142.  
  143. Internet RFC 1750, available on a web site near you.
  144. Bruce Schneier's "Applied Cryptography", available in fine bookstores everywhere.
  145.  
  146. #endif
  147.  
  148. //
  149. // The Distiller object, the first stage generator
  150. //
  151. Distiller::Distiller()
  152. {
  153.     Init();                // Initialize the object
  154. }
  155.  
  156. void Distiller::Init()
  157. {
  158.     // The only reason this routine exists, as opposed to
  159.     // keeping it in the constructor is that I thought it might be
  160.     // useful to be able to re-init an existing distiller.
  161.     
  162.     SetEntropy(0);
  163.     shsInit(&shs);
  164. }
  165.  
  166. int Distiller::AddData(void *start, long length, int decibits)
  167. {
  168.     totalEntropy += decibits;                            // Update the guess
  169.     shsUpdate(&shs, (unsigned char *) start, length);    // Hash in the observation
  170.     
  171.     return totalEntropy;
  172. }
  173.  
  174. void Distiller::GetHash(unsigned char hash[HASHLEN])
  175. {
  176.     SHS_CTX context = shs;                                // Make a copy of the hash state
  177.     shsFinal(&context, hash);                            // Finalize the copied hash.
  178. }
  179.  
  180. //
  181. // This is the Grinder object, the second stage of the generator
  182. //
  183.  
  184. Grinder::Grinder()
  185. {
  186.     numberPlace = 0;
  187.     newPlace = 0;
  188.     InitNums();
  189. }
  190.  
  191. Grinder::Grinder(void *theStuff, long stuffLen)
  192. {
  193.     // We don't actually ever use this constructor, but here it is, in case
  194.     // you want to make a Grinder and give it some stuff.
  195.     
  196.     numberPlace = 0;
  197.     newPlace = 0;
  198.     InitNums();
  199.     AddStuff(theStuff, stuffLen);
  200. }
  201.  
  202. void Grinder::InitNums()
  203. {
  204.     for (int i = 0; i < 256; i++)            // put the numbers 255 downto 0 into the array
  205.         numbers[i] = ~i;
  206. }
  207.  
  208. void Grinder::AddStuff(void *theStuff, long stuffLen)
  209. {
  210.     int             i;
  211.     int             j = 0;
  212.     int                stuffPlace = 0;
  213.     
  214.     for (i = 0; i < 256; i++)
  215.     {
  216.         j = (numbers[i] + ((unsigned char *) theStuff)[stuffPlace] + j);
  217.         j &= 0xff;
  218.         
  219.         unsigned char t = numbers[i];                        // Swap the appropriate number
  220.         numbers[i] = numbers[j];
  221.         numbers[j] = t;
  222.         
  223.         stuffPlace = (stuffPlace + 1) % stuffLen;
  224.     }
  225.     
  226.     for (i = 0; i < 256; i++)                        // Turn the crank through a complete
  227.         Turn();                                        // revolution to thoroughly mix up the
  228.                                                     // numbers. Studies show that this lessens
  229.                                                     // the effect of weakly random stuff.
  230. }
  231.  
  232. unsigned char Grinder::Turn()
  233. {
  234.     // The actual work is done here for the second stage. This is what
  235.     // pops off random bytes. We spin this when we add more stuff to 
  236.     // stir it up.
  237.     
  238.     register unsigned char t;
  239.     
  240.     // We're going to swap two cells of stuff and numbers. We walk around the
  241.     // array, picking the next spot. The place we're going to swap it with
  242.     // is selected with the statements below:
  243.     
  244.     newPlace = newPlace + numbers[numberPlace];
  245.     newPlace &= 0xff;    // mod 256
  246.     
  247.     t = numbers[numberPlace];                // Swap number cells
  248.     numbers[numberPlace] = numbers[newPlace];
  249.     numbers[newPlace] = t;
  250.     
  251.     t += numbers[numberPlace];                // Add in the other cell
  252.     t &= 0xff;
  253.     
  254.     numberPlace = (numberPlace + 1) & 0xff;    // Find the next cell to play with
  255.     
  256.     return numbers[t];
  257. }
  258.  
  259. void Grinder::GetRandom(void *thePlace, long length)
  260. {
  261.     unsigned char *x = (unsigned char *) thePlace;
  262.     
  263.     for (int i = 0; i < length; i++)                // Just step out N bytes
  264.         *x++ = Turn();
  265. }
  266.  
  267.  
  268. unsigned char Randomizer::Byte()
  269. {
  270.     return Turn();
  271. }
  272.  
  273. unsigned short Randomizer::Word()
  274. {
  275.     return (Turn() << 8) | Turn();
  276. }
  277.  
  278. unsigned long Randomizer::Long()
  279. {
  280.     return    (Turn() << 24) |
  281.             (Turn() << 16) |
  282.             (Turn() <<  8) |
  283.             Turn();
  284. }
  285.  
  286. void Randomizer::AddSeed(void *seed, int seedLen, int entropyGuessInDecibits)
  287. {
  288.     if (entropyGuessInDecibits < 0)
  289.         entropyGuessInDecibits = TOTALENTROPY;
  290.     
  291.     AddData(seed, seedLen, entropyGuessInDecibits);
  292.     
  293.     if (GetEntropy() > TOTALENTROPY)
  294.     {
  295.         unsigned char    hash[HASHLEN];
  296.         
  297.         GetHash(hash);
  298.         AddStuff(hash, HASHLEN);
  299.         
  300.         SetEntropy(GetEntropy() - TOTALENTROPY);
  301.     }
  302. }
  303.  
  304. Randomizer::Randomizer()
  305. {
  306.     busy = 0;
  307. }
  308.  
  309. void Randomizer::GetState(RandomState *state)
  310. {
  311.     state->distillerEntropy    = GetEntropy();
  312.     state->numberPlace        = numberPlace;
  313.     state->newPlace            = newPlace;
  314.     state->still            = shs;
  315.  
  316.     for (int i = 0; i < 256; i++)
  317.         state->numbers[i] = numbers[i];
  318. }
  319.  
  320. void Randomizer::SetState(RandomState *state)
  321. {
  322.     SetEntropy(state->distillerEntropy);
  323.     numberPlace        = state->numberPlace;
  324.     newPlace        = state->newPlace;
  325.     shs                = state->still;
  326.  
  327.     for (int i = 0; i < 256; i++)
  328.         numbers[i] = state->numbers[i];
  329. }
  330.  
  331.